package requestId

import (
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

type Generator func() string

type HeaderStrKey string

type options struct {
	// Generator defines a function to generate an ID.
	// Optional. Default: func() string {
	//   return uuid.New().String()
	// }
	generator Generator
	headerKey HeaderStrKey
}

type Option interface {
	apply(*options)
}

type funcOption struct {
	fn func(*options)
}

func (f *funcOption) apply(o *options) {
	f.fn(o)
}

func newFuncOption(fn func(*options)) Option {
	return &funcOption{fn: fn}
}

func WithGenerator(generator Generator) Option {
	return newFuncOption(func(o *options) {
		o.generator = generator
	})
}

func WithHeaderKey(key HeaderStrKey) Option {
	return newFuncOption(func(o *options) {
		o.headerKey = key
	})
}

var headerXRequestID string

func New(opts ...Option) gin.HandlerFunc {
	o := &options{
		generator: func() string {
			return uuid.New().String()
		},
		headerKey: "X-Request-ID",
	}
	for _, opt := range opts {
		opt.apply(o)
	}
	headerXRequestID = string(o.headerKey)

	return func(c *gin.Context) {
		rid := c.GetHeader(headerXRequestID)
		if rid == "" {
			rid = o.generator()
		}
		c.Header(headerXRequestID, rid)
		c.Set(headerXRequestID, rid)
		c.Next()
	}
}

func Get(c *gin.Context) string {
	if v, ok := c.Get(headerXRequestID); ok {
		return v.(string)
	}
	return ""
}
